package com.owc.common.tool;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * Created by xiaoming
 */
@Component
@ConfigurationProperties(prefix = "idgenerater")
public class IDGenerater {
	private static final long serialVersionUID = 6239716958876912625L;
	private final long twepoch = 1420041600000L;
	private final long workerIdBits = 5L;
	private final long datacenterIdBits = 5L;
	private final long maxWorkerId = 31L;
	private final long maxDatacenterId = 31L;
	private final long sequenceBits = 12L;
	private final long workerIdShift = 12L;
	private final long datacenterIdShift = 17L;
	private final long timestampLeftShift = 22L;
	private final long sequenceMask = 4095L;
	private long workerId;
	private long datacenterId;
	private long sequence = 0L;
	private long lastTimestamp = -1L;

	public IDGenerater(IDGenerater idGenerater) {
		if(idGenerater.workerId <= 31L && idGenerater.workerId >= 0L) {
			if(idGenerater.datacenterId <= 31L && idGenerater.datacenterId >= 0L) {
				this.workerId = idGenerater.workerId;
				this.datacenterId = idGenerater.datacenterId;
			} else {
				throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", new Object[]{Long.valueOf(31L)}));
			}
		} else {
			throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", new Object[]{Long.valueOf(31L)}));
		}
	}

	public synchronized long nextId() {
		long timestamp = this.timeGen();
		if(timestamp < this.lastTimestamp) {
			throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", new Object[]{Long.valueOf(this.lastTimestamp - timestamp)}));
		} else {
			if(this.lastTimestamp == timestamp) {
				this.sequence = this.sequence + 1L & 4095L;
				if(this.sequence == 0L) {
					timestamp = this.tilNextMillis(this.lastTimestamp);
				}
			} else {
				this.sequence = 0L;
			}

			this.lastTimestamp = timestamp;
			return timestamp - 1420041600000L << 22 | this.datacenterId << 17 | this.workerId << 12 | this.sequence;
		}
	}

	protected long tilNextMillis(long lastTimestamp) {
		long timestamp;
		for(timestamp = this.timeGen(); timestamp <= lastTimestamp; timestamp = this.timeGen()) {
			;
		}

		return timestamp;
	}

	protected long timeGen() {
		return System.currentTimeMillis();
	}


	public long getWorkerId() {
		return this.workerId;
	}

	public void setWorkerId(long workerId) {
		this.workerId = workerId;
	}

	public long getDatacenterId() {
		return this.datacenterId;
	}

	public void setDatacenterId(long datacenterId) {
		this.datacenterId = datacenterId;
	}

	public IDGenerater() {
	}
}
